﻿using EBA.Aspects;
using Microsoft.Build.Construction;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
using Mono.Cecil;
using Mono.Cecil.Cil;
using Mono.Collections.Generic;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;


namespace EBA.MsBuildTask
{
    public class WeavingTask : Task
    {
        [Required]
        public string OutputFile
        {
            get;
            set;
        }

        public override bool Execute()
        {
            //TODO: Static调用Instance方法，两只个都有IPostMethodInvoke的时候，Static的IPostMethodInvoke的context无法获取对应示例

            this.WriteMessage("Starting to mix interceptors for " + this.OutputFile + ".");

            var resolver = new AssemblyResolver();

            var bin = Path.GetDirectoryName(this.OutputFile);
            resolver.AddSearchDirectory(bin);

            var readerParameters = new ReaderParameters { ReadSymbols = true, AssemblyResolver = resolver };

            AssemblyDefinition assembly = AssemblyDefinition.ReadAssembly(this.OutputFile, readerParameters);

            foreach (Mono.Cecil.TypeDefinition item in assembly.MainModule.Types)
            {
                var typeName = item.Name;
                var typeDefinitions = GetTypeDefinitions(assembly.MainModule, item.CustomAttributes);

                var hasPreClassInvoke = item.IsSealed && item.IsAbstract ? false : typeDefinitions
                     .SelectMany(i => i.Interfaces)
                     .Any(i => new string[] { "EBA.Aspects.IPreClassInvoke" }.Contains(i.FullName));

                foreach (var method in item.Methods)
                {
                    //  this.Log.LogWarning("Method:" + method.Name);
                    if (method.IsConstructor && hasPreClassInvoke)
                    {
                        this.WriteMessage("Adding PreClassInvoke for [" + typeName + "].");
                        var worker = method.Body.GetILProcessor();
                        var head = method.Body.Instructions[0];

                        //1.var context = new InterceptionContext(){TypeName=item.DeclaringType,MethodName=method.Name};
                        BuildContext(assembly, item, method, worker, head);

                        //2. Interceptors.OnPreClassInvoke(context)
                        worker.InsertBefore(head, worker.Create(OpCodes.Ldloc_0));
                        Instruction callPreClass = worker.Create(OpCodes.Call, assembly.MainModule.Import(typeof(Interceptors).GetMethod("OnPreClassInvoke")));
                        worker.InsertBefore(head, callPreClass);
                    }
                    else
                    {

                        var interfaces = GetTypeDefinitions(assembly.MainModule, method.CustomAttributes)
                            .SelectMany(i => i.Interfaces)
                            .ToList();

                        var hasPreMethodInvoke = interfaces.Any(i => new string[] { "EBA.Aspects.IPreMethodInvoke" }.Contains(i.FullName));
                        var hasPostMethodInvoke = interfaces.Any(i => new string[] { "EBA.Aspects.IPostMethodInvoke" }.Contains(i.FullName));

                        if (hasPreMethodInvoke || hasPostMethodInvoke)
                        {
                            var worker = method.Body.GetILProcessor();
                            var head = method.Body.Instructions[0];

                            //1.var context = new InterceptionContext(){TypeName=item.DeclaringType,MethodName=method.Name};
                            var context = BuildContext(assembly, item, method, worker, head);

                            if (hasPreMethodInvoke)
                            {
                                this.WriteMessage("Adding PreMethodInvoke for [" +typeName +"." + method.Name + "].");
                                //2. Interceptors.OnPreMethodInvoke(context);
                                worker.InsertBefore(head, worker.Create(OpCodes.Ldloc_S, context));
                                Instruction callPreMethod = worker.Create(OpCodes.Call, assembly.MainModule.Import(typeof(Interceptors).GetMethod("OnPreMethodInvoke")));
                                worker.InsertBefore(head, callPreMethod);
                            }


                            if (hasPostMethodInvoke)
                            {
                                //3. Interceptors.OnPostMethodInvoke(context)
                                foreach (var i in method.Body.Instructions.ToArray())
                                {
                                    if (i.OpCode == OpCodes.Ret)
                                    {
                                        this.WriteMessage("Adding PostMethodInvoke for ["  + typeName +"." + method.Name + "].");
                                        //3. Interceptors.OnPostMethodInvoke(context); 
                                        // worker.InsertBefore(i, worker.Create(OpCodes.Stloc));
                                        worker.InsertBefore(head, worker.Create(OpCodes.Ldloc_S, context));
                                        var callOnPostMethodInvoke = worker.Create(OpCodes.Call, assembly.MainModule.Import(typeof(Interceptors).GetMethod("OnPostMethodInvoke")));
                                        worker.InsertBefore(i, callOnPostMethodInvoke);
                                    }
                                }

                            }

                        }
                    }
                }
            }


            var writerParameters = new WriterParameters { WriteSymbols = true };
            assembly.Write(this.OutputFile, writerParameters);

            this.WriteMessage("Ended to mix interceptors for " + this.OutputFile);
            return true;
        }

        Dictionary<string, TypeDefinition> TypeDefinitions = new Dictionary<string, TypeDefinition>();
        Dictionary<string, AssemblyDefinition> AssemblyDefinitions = new Dictionary<string, AssemblyDefinition>();

        private List<TypeDefinition> GetTypeDefinitions(ModuleDefinition moduleDefinition, Collection<CustomAttribute> customAttributes)
        {
            var typeDefinitions = new List<TypeDefinition>();

            foreach (var attr in customAttributes.Select(i => i.AttributeType))
            {
                if (attr is TypeDefinition)
                {
                    typeDefinitions.Add(attr as TypeDefinition);
                }
                else if (attr is TypeReference)
                {
                    TypeDefinition typeDefinition;

                    if (this.TypeDefinitions.TryGetValue(attr.FullName, out typeDefinition) == false)
                    {
                        AssemblyDefinition assemblyDefinition;
                        if (this.AssemblyDefinitions.TryGetValue(attr.Scope.Name, out assemblyDefinition) == false)
                        {
                            var assemblyLibraryName = Path.Combine(Path.GetDirectoryName(this.OutputFile), attr.Scope.Name + ".dll");
                            var assemblyExeName = Path.Combine(Path.GetDirectoryName(this.OutputFile), attr.Scope.Name + ".exe");
                            if (File.Exists(assemblyLibraryName))
                            {
                                assemblyDefinition = AssemblyDefinition.ReadAssembly(assemblyLibraryName);
                                this.AssemblyDefinitions.Add(attr.Scope.Name, assemblyDefinition);
                            }
                            else if (File.Exists(assemblyExeName))
                            {
                                assemblyDefinition = AssemblyDefinition.ReadAssembly(assemblyExeName);
                                this.AssemblyDefinitions.Add(attr.Scope.Name, assemblyDefinition);
                            }

                        }

                        if (assemblyDefinition != null)
                        {
                            typeDefinition = assemblyDefinition.MainModule.GetType(attr.FullName);

                        }
                    }


                    if (typeDefinition != null)
                    {
                        typeDefinitions.Add(typeDefinition);
                    }
                }
            }

            return typeDefinitions;
        }




        private static VariableDefinition BuildContext(AssemblyDefinition assembly, Mono.Cecil.TypeDefinition item, MethodDefinition method, ILProcessor worker, Instruction placeholder)
        {
            //#region 1. var context = New InterceptionContext();

            //Type interceptionContextType = typeof(InterceptionContext);
            //var interceptionContextTypeReference = assembly.MainModule.Import(interceptionContextType);
            //method.Body.Variables.Add(new VariableDefinition(interceptionContextTypeReference));
            //worker.InsertBefore(placeholder, worker.Create(OpCodes.Newobj, assembly.MainModule.Import(interceptionContextType.GetConstructors().First())));

            //#endregion

            //#region 2. var context.TypeName = item.DeclaringType;

            //worker.InsertBefore(placeholder, worker.Create(OpCodes.Stloc_0));
            //worker.InsertBefore(placeholder, worker.Create(OpCodes.Ldloc_0));
            //worker.InsertBefore(placeholder, worker.Create(OpCodes.Ldstr, item.FullName + "," + assembly.FullName));
            //worker.InsertBefore(placeholder, worker.Create(OpCodes.Callvirt, assembly.MainModule.Import(interceptionContextType.GetMethod("set_TypeName"))));

            //#endregion

            //#region 3. context.MethodName = method.Name;
            //worker.InsertBefore(placeholder, worker.Create(OpCodes.Nop));
            //worker.InsertBefore(placeholder, worker.Create(OpCodes.Ldloc_0));
            //worker.InsertBefore(placeholder, worker.Create(OpCodes.Ldstr, method.Name));
            //worker.InsertBefore(placeholder, worker.Create(OpCodes.Callvirt, assembly.MainModule.Import(interceptionContextType.GetMethod("set_MethodName"))));


            //#endregion


            Type interceptionContextType = typeof(InterceptionContext);
            var interceptionContextTypeReference = assembly.MainModule.Import(interceptionContextType);
            var typeReference = assembly.MainModule.Import(typeof(Type));

            var parametersType = typeof(Type[]);
            var parametersTypeReference = assembly.MainModule.Import(parametersType);

            var index = method.Body.Variables.Count;

            //InterceptionContext  eba_interception_context;
            var eba_interception_context = new VariableDefinition("eba_interception_context", interceptionContextTypeReference);
            method.Body.Variables.Add(eba_interception_context);
            //Type eba_interception_context_type;
            var eba_interception_context_type = new VariableDefinition("eba_interception_context_type", typeReference);
            method.Body.Variables.Add(eba_interception_context_type);
            //Type[] eba_interception_context_method_parameters;
            var eba_interception_context_method_parameters = new VariableDefinition("eba_interception_context_method_parameters", parametersTypeReference);
            method.Body.Variables.Add(eba_interception_context_method_parameters);

            var typeofReference = assembly.MainModule.Import(typeof(Type).GetMethod("GetTypeFromHandle", new Type[] { typeof(System.RuntimeTypeHandle) }));

            //eba_interception_context = new InterceptionContext();
            worker.InsertBefore(placeholder, worker.Create(OpCodes.Nop));
            worker.InsertBefore(placeholder, worker.Create(OpCodes.Newobj, assembly.MainModule.Import(interceptionContextType.GetConstructors().First())));
            worker.InsertBefore(placeholder, worker.Create(OpCodes.Stloc_S, eba_interception_context));


            //  worker.InsertBefore(placeholder, worker.Create(OpCodes.Ldloc_S, "eba_interception_context"));

            //eba_interception_context_type = typeof(Item)
            worker.InsertBefore(placeholder, worker.Create(OpCodes.Ldtoken, item));

            worker.InsertBefore(placeholder, worker.Create(OpCodes.Call, typeofReference));
            worker.InsertBefore(placeholder, worker.Create(OpCodes.Stloc_S, eba_interception_context_type));

            //eba_interception_context.Type = eba_interception_context_type;
            worker.InsertBefore(placeholder, worker.Create(OpCodes.Ldloc_S, eba_interception_context));
            worker.InsertBefore(placeholder, worker.Create(OpCodes.Ldloc_S, eba_interception_context_type));
            worker.InsertBefore(placeholder, worker.Create(OpCodes.Callvirt, assembly.MainModule.Import(typeof(InterceptionContext).GetMethod("set_Type"))));
            worker.InsertBefore(placeholder, worker.Create(OpCodes.Nop));

            //eba_interception_context.Method = eba_interception_context_type.getMethod("Do",new Type[] { });
            worker.InsertBefore(placeholder, worker.Create(OpCodes.Ldloc_S, eba_interception_context));
            worker.InsertBefore(placeholder, worker.Create(OpCodes.Ldloc_S, eba_interception_context_type));
            worker.InsertBefore(placeholder, worker.Create(OpCodes.Ldstr, method.Name));


            //context.Method = type.GetMethod("Do",
            //    System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Static,
            //    Type.DefaultBinder,
            //    new Type[] { typeof(string), typeof(int) }, null
            //    );

            //Interceptors.OnPreMethodInvoke(context);

            //System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Static
            // var flags = System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Static;

            worker.InsertBefore(placeholder, worker.Create(OpCodes.Ldc_I4_S, (sbyte)60));



            //Type.DefaultBinder
             worker.InsertBefore(placeholder, worker.Create(OpCodes.Call, assembly.MainModule.Import(typeof(Type).GetMethod("get_DefaultBinder"))));
           // worker.InsertBefore(placeholder, worker.Create(OpCodes.Ldnull));

            var len = method.Parameters.Count;
            worker.InsertBefore(placeholder, CreateLdc(worker, len));
            worker.InsertBefore(placeholder, worker.Create(OpCodes.Newarr, typeReference));
            worker.InsertBefore(placeholder, worker.Create(OpCodes.Stloc_S, eba_interception_context_method_parameters));

            for (var i = 0; i < len; i++)
            {
                worker.InsertBefore(placeholder, worker.Create(OpCodes.Ldloc_S, eba_interception_context_method_parameters));
                worker.InsertBefore(placeholder, CreateLdc(worker, i));
                worker.InsertBefore(placeholder, worker.Create(OpCodes.Ldtoken, method.Parameters[i].ParameterType));
                worker.InsertBefore(placeholder, worker.Create(OpCodes.Call, typeofReference));
                worker.InsertBefore(placeholder, worker.Create(OpCodes.Stelem_Ref));
            }

            worker.InsertBefore(placeholder, worker.Create(OpCodes.Ldloc_S, eba_interception_context_method_parameters));

            //System.Reflection.ParameterModifier[]
            worker.InsertBefore(placeholder, worker.Create(OpCodes.Ldnull));

            worker.InsertBefore(placeholder, worker.Create(OpCodes.Callvirt, assembly.MainModule.Import(typeof(Type).GetMethod("GetMethod", new Type[] { typeof(string), typeof(System.Reflection.BindingFlags), typeof(System.Reflection.Binder), typeof(Type[]), typeof(System.Reflection.ParameterModifier[]) }))));
            worker.InsertBefore(placeholder, worker.Create(OpCodes.Callvirt, assembly.MainModule.Import(typeof(InterceptionContext).GetMethod("set_Method"))));


            //.method public hidebysig instance void  Hello(string name,
            //                                              int32 age) cil managed
            //{
            //  .custom instance void ConsoleApplication1.PreMethodInvokeAttribute::.ctor() = ( 01 00 00 00 ) 
            //  // Code size       36 (0x24)
            //  .maxstack  4
            //  .locals init ([0] class [EBA]EBA.Aspects.InterceptionContext interceptionContext,
            //           [1] object[] CS$0$0000)
            //  IL_0000:  nop
            //  IL_0001:  newobj     instance void [EBA]EBA.Aspects.InterceptionContext::.ctor()
            //  IL_0006:  stloc.0

            //  IL_0007:  ldloc.0

            //  IL_0008:  ldc.i4.2
            //  IL_0009:  newarr     [mscorlib]System.Object
            //  IL_000e:  stloc.1

            //  IL_000f:  ldloc.1
            //  IL_0010:  ldc.i4.0
            //  IL_0011:  ldarg.1
            //  IL_0012:  stelem.ref

            //  IL_0013:  ldloc.1
            //  IL_0014:  ldc.i4.1
            //  IL_0015:  ldarg.2
            //  IL_0016:  box        [mscorlib]System.Int32
            //  IL_001b:  stelem.ref

            //  IL_001c:  ldloc.1
            //  IL_001d:  callvirt   instance void [EBA]EBA.Aspects.InterceptionContext::set_Parameters(object[])
            //  IL_0022:  nop
            //  IL_0023:  ret
            //} // end of method MyClass::Hello

    
            worker.InsertBefore(placeholder, worker.Create(OpCodes.Ldloc_S, eba_interception_context));

            var eba_method_arguments = new VariableDefinition("eba_method_arguments", assembly.MainModule.Import(typeof(object[])));
            worker.Body.Variables.Add(eba_method_arguments);

            // worker.InsertBefore(placeholder, worker.Create(OpCodes.Ldloc_S, eba_interception_context));

            //worker.Emit(OpCodes.Ldloc_S, eba_method_arguments);

            worker.InsertBefore(placeholder, CreateLdc(worker, method.Parameters.Count));
            worker.InsertBefore(placeholder, worker.Create(OpCodes.Newarr, assembly.MainModule.Import(typeof(object))));
            worker.InsertBefore(placeholder, worker.Create(OpCodes.Stloc_S, eba_method_arguments));


            for (var i = 0; i < method.Parameters.Count; i++)
            {
               
                worker.InsertBefore(placeholder, worker.Create(OpCodes.Ldloc_S, eba_method_arguments));
                worker.InsertBefore(placeholder, CreateLdc(worker, i));
                worker.InsertBefore(placeholder, worker.Create(OpCodes.Ldarg_S,method.Parameters[i]));

                if (method.Parameters[i].ParameterType.IsValueType)
                {
                    worker.InsertBefore(placeholder,worker.Create(OpCodes.Box, assembly.MainModule.Import(method.Parameters[i].ParameterType)));
                }

                worker.InsertBefore(placeholder, worker.Create(OpCodes.Stelem_Ref));
            }

         
            worker.InsertBefore(placeholder, worker.Create(OpCodes.Ldloc_S, eba_method_arguments));
            worker.InsertBefore(placeholder, worker.Create(OpCodes.Callvirt, assembly.MainModule.Import(typeof(InterceptionContext).GetMethod("set_Parameters"))));
           


            return eba_interception_context;

            //.method public hidebysig static void  Do(string source,
            //                                         int32 i) cil managed
            //{
            //  // Code size       290 (0x122)
            //  .maxstack  6
            //  .locals init ([0] string s1,
            //           [1] string s2,
            //           [2] int32 s3,
            //           [3] int32 s4,
            //           [4] class [EBA]EBA.Aspects.InterceptionContext context,
            //           [5] class [mscorlib]System.Type 'type',
            //           [6] class [mscorlib]System.Type[] CS$0$0000)
            //  IL_0000:  nop
            //  IL_0001:  ldarg.0
            //  IL_0002:  stloc.0
            //  IL_0003:  ldstr      ""
            //  IL_0008:  stloc.1
            //  IL_0009:  ldc.i4.1
            //  IL_000a:  stloc.2
            //  IL_000b:  ldc.i4.4
            //  IL_000c:  stloc.3
            //  IL_000d:  newobj     instance void [EBA]EBA.Aspects.InterceptionContext::.ctor()
            //  IL_0012:  stloc.s    context
            //  IL_0014:  ldtoken    ConsoleApplication1.Helper
            //  IL_0019:  call       class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
            //  IL_001e:  stloc.s    'type'

            //  IL_0020:  ldloc.s    context
            //  IL_0022:  ldloc.s    'type'
            //  IL_0024:  callvirt   instance void [EBA]EBA.Aspects.InterceptionContext::set_Type(class [mscorlib]System.Type)

            //  IL_0029:  nop
            //  IL_002a:  ldloc.s    context
            //  IL_002c:  ldloc.s    'type'
            //  IL_002e:  ldstr      "Do"
            //  IL_0033:  ldc.i4.s   15
            //  IL_0035:  newarr     [mscorlib]System.Type
            //  IL_003a:  stloc.s    CS$0$0000
            //  IL_003c:  ldloc.s    CS$0$0000
            //  IL_003e:  ldc.i4.0
            //  IL_003f:  ldtoken    [mscorlib]System.String
            //  IL_0044:  call       class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
            //  IL_0049:  stelem.ref
            //  IL_004a:  ldloc.s    CS$0$0000
            //  IL_004c:  ldc.i4.1
            //  IL_004d:  ldtoken    [mscorlib]System.Int32
            //  IL_0052:  call       class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
            //  IL_0057:  stelem.ref
            //  IL_0058:  ldloc.s    CS$0$0000
            //  IL_005a:  ldc.i4.2
            //  IL_005b:  ldtoken    [mscorlib]System.DateTime
            //  IL_0060:  call       class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
            //  IL_0065:  stelem.ref
            //  IL_0066:  ldloc.s    CS$0$0000
            //  IL_0068:  ldc.i4.3
            //  IL_0069:  ldtoken    [mscorlib]System.Int32
            //  IL_006e:  call       class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
            //  IL_0073:  stelem.ref
            //  IL_0074:  ldloc.s    CS$0$0000
            //  IL_0076:  ldc.i4.4
            //  IL_0077:  ldtoken    [mscorlib]System.DBNull
            //  IL_007c:  call       class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
            //  IL_0081:  stelem.ref
            //  IL_0082:  ldloc.s    CS$0$0000
            //  IL_0084:  ldc.i4.5
            //  IL_0085:  ldtoken    [mscorlib]System.String
            //  IL_008a:  call       class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
            //  IL_008f:  stelem.ref
            //  IL_0090:  ldloc.s    CS$0$0000
            //  IL_0092:  ldc.i4.6
            //  IL_0093:  ldtoken    [mscorlib]System.Int32
            //  IL_0098:  call       class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
            //  IL_009d:  stelem.ref
            //  IL_009e:  ldloc.s    CS$0$0000
            //  IL_00a0:  ldc.i4.7
            //  IL_00a1:  ldtoken    [mscorlib]System.DateTime
            //  IL_00a6:  call       class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
            //  IL_00ab:  stelem.ref
            //  IL_00ac:  ldloc.s    CS$0$0000
            //  IL_00ae:  ldc.i4.8
            //  IL_00af:  ldtoken    [mscorlib]System.Int32
            //  IL_00b4:  call       class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
            //  IL_00b9:  stelem.ref
            //  IL_00ba:  ldloc.s    CS$0$0000
            //  IL_00bc:  ldc.i4.s   9
            //  IL_00be:  ldtoken    [mscorlib]System.DBNull
            //  IL_00c3:  call       class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
            //  IL_00c8:  stelem.ref
            //  IL_00c9:  ldloc.s    CS$0$0000
            //  IL_00cb:  ldc.i4.s   10
            //  IL_00cd:  ldtoken    [mscorlib]System.String
            //  IL_00d2:  call       class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
            //  IL_00d7:  stelem.ref
            //  IL_00d8:  ldloc.s    CS$0$0000
            //  IL_00da:  ldc.i4.s   11
            //  IL_00dc:  ldtoken    [mscorlib]System.Int32
            //  IL_00e1:  call       class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
            //  IL_00e6:  stelem.ref
            //  IL_00e7:  ldloc.s    CS$0$0000
            //  IL_00e9:  ldc.i4.s   12
            //  IL_00eb:  ldtoken    [mscorlib]System.DateTime
            //  IL_00f0:  call       class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
            //  IL_00f5:  stelem.ref
            //  IL_00f6:  ldloc.s    CS$0$0000
            //  IL_00f8:  ldc.i4.s   13
            //  IL_00fa:  ldtoken    [mscorlib]System.Int32
            //  IL_00ff:  call       class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
            //  IL_0104:  stelem.ref
            //  IL_0105:  ldloc.s    CS$0$0000
            //  IL_0107:  ldc.i4.s   14
            //  IL_0109:  ldtoken    [mscorlib]System.DBNull
            //  IL_010e:  call       class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
            //  IL_0113:  stelem.ref
            //  IL_0114:  ldloc.s    CS$0$0000
            //  IL_0116:  callvirt   instance class [mscorlib]System.Reflection.MethodInfo [mscorlib]System.Type::GetMethod(string,
            //                                                                                                              class [mscorlib]System.Type[])
            //  IL_011b:  callvirt   instance void [EBA]EBA.Aspects.InterceptionContext::set_Method(class [mscorlib]System.Reflection.MethodInfo)
            //  IL_0120:  nop
            //  IL_0121:  ret
            //} // end of method Helper::Do

            

        }

        private static Instruction CreateLdc(ILProcessor worker, int value)
        {
            switch (value)
            {
                case 0:
                    return worker.Create(OpCodes.Ldc_I4_0);
                case 1:
                    return worker.Create(OpCodes.Ldc_I4_1);
                case 2:
                    return worker.Create(OpCodes.Ldc_I4_2);
                case 3:
                    return worker.Create(OpCodes.Ldc_I4_3);
                case 4:
                    return worker.Create(OpCodes.Ldc_I4_4);
                case 5:
                    return worker.Create(OpCodes.Ldc_I4_5);
                case 6:
                    return worker.Create(OpCodes.Ldc_I4_6);
                case 7:
                    return worker.Create(OpCodes.Ldc_I4_7);
                case 8:
                    return worker.Create(OpCodes.Ldc_I4_8);
                default:
                    return worker.Create(OpCodes.Ldc_I4_S, (sbyte)value);
            }
        }

        private static Instruction CreateLdarg(ILProcessor worker, int value)
        {
            switch (value)
            {
                case 0:
                    return worker.Create(OpCodes.Ldarg_0);
                case 1:
                    return worker.Create(OpCodes.Ldarg_1);
                case 2:
                    return worker.Create(OpCodes.Ldarg_2);
                case 3:
                    return worker.Create(OpCodes.Ldarg_3);
                default:

                    return worker.Create(OpCodes.Ldarg, value);
            }
        }

        private void WriteMessage(string message)
        {
            try
            {
                this.Log.LogMessage(MessageImportance.High, "[EBA] {0}", message);
            }
            catch
            {
                Console.WriteLine("[EBA] {0}", message);
            }
        }
    }
}